package com.example.ephuizi.stl.util.string_3d;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;

import com.example.ephuizi.stl.util.STLFile;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by ephuizi@gmail.com on 2015/11/5.
 */
public class StringConvert3D {
    private static final float USB_LENGTH = 16f;
    private static final float USB_WIDTH = 16f;
    private static final float USB_HEIGHT = 8f;

    private static final float USB_H_LENGTH = 12.4f;// 内槽长
    private static final float USB_H_WIDTH = 10f;// 内槽宽
    private static final float USB_H_HEIGHT = 4f;// 内槽高

    private static final int SIDE_WIDTH = 100;

    private static final float INSIDE_THICKNESS_RATE = 0.6f;

    public static Data3D convert3DDifBottom(List<DrawStringParam> params) {
        Data3D data3D = null;
        for (int i = 0; i < params.size(); i++) {
            DrawStringParam param = params.get(i);
            int fontSize = (int) (SIDE_WIDTH * param.scale);

            Paint paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setTextSize(SIDE_WIDTH * param.scale);
            paint.setTypeface(param.typeface);
            paint.setColor(param.color);
            for (int j = 0; j < param.target.length(); j++) {
                Data3D char3D = convert3D(param.target.charAt(j), paint, fontSize, param.scale);
                if (data3D == null)
                    data3D = char3D;
                else {
                    for (int k = 0; k < char3D.tris.size(); k++) {
                        Triangle tri = char3D.tris.get(k);
                        tri.toMoveX(data3D.max.x);
                    }
                    char3D.max.x += data3D.max.x;
                    data3D.max.x = char3D.max.x;
                    data3D.tris.addAll(char3D.tris);
                }
            }
        }
        return data3D;
    }

    /**
     * 将单个字符3D化
     *
     * @return
     */
    private static Data3D convert3D(char c, Paint paint, int fontSize, float scale) {
        int imgWidth = fontSize;
        Bitmap bitmap = Bitmap.createBitmap(imgWidth, SIDE_WIDTH, Bitmap.Config.ARGB_8888);
        for (int x = 0; x < bitmap.getWidth(); x++) {
            for (int y = 0; y < bitmap.getHeight(); y++) {
                bitmap.setPixel(x, y, Color.WHITE);
            }
        }
        Canvas canvas = new Canvas(bitmap);
        int baseline = SIDE_WIDTH / 6;
        canvas.drawText(String.valueOf(c), nextTextBeginDraw(bitmap), SIDE_WIDTH - baseline, paint);
        Data3D data3D = convert3D0(bitmap);
        formalImg3D(data3D, scale);
        return data3D;
    }

    /**
     * 根据参数将字符串转成3D,底部是完全的
     *
     * @param params
     * @return
     */
    public static Data3D convert3DFullBottom(List<DrawStringParam> params) {
        int sumLength = 0;
        for (int i = 0; i < params.size(); i++) {
            DrawStringParam param = params.get(i);
            for (int j = 0; j < param.target.length(); j++) {
                sumLength += SIDE_WIDTH * param.scale;
            }
        }

        Bitmap bitmap = Bitmap.createBitmap(sumLength, SIDE_WIDTH, Bitmap.Config.ARGB_8888);
        for (int x = 0; x < bitmap.getWidth(); x++) {
            for (int y = 0; y < bitmap.getHeight(); y++) {
                bitmap.setPixel(x, y, Color.WHITE);
            }
        }

        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        int baseline = SIDE_WIDTH / 6;
        for (int i = 0; i < params.size(); i++) {
            DrawStringParam param = params.get(i);
            paint.setTextSize(SIDE_WIDTH * param.scale);
            paint.setTypeface(param.typeface);
            paint.setColor(param.color);
            for (int j = 0; j < param.target.length(); j++) {
                canvas.drawText(String.valueOf(param.target.charAt(j)), nextTextBeginDraw(bitmap), SIDE_WIDTH - baseline, paint);
            }
        }
        Data3D data3D = convert3D0(bitmap);
        formalImg3D(data3D, 1f);
        return data3D;
    }

    /**
     * 调整模型在xy平面的大小,以适合usb头
     *
     * @param data3D
     * @param scale
     */
    private static void formalImg3D(Data3D data3D, float scale) {
        List<Triangle> list = data3D.tris;
        // y变化率
        float scaleRateY = USB_LENGTH * scale / (data3D.max.y - data3D.min.y);
        for (int i = 0; i < list.size(); i++) {
            Triangle tri = list.get(i);
            tri.toScaleX(scaleRateY);
            tri.toScaleY(scaleRateY);
        }
        data3D.calculateMaxAndMin();
    }

    private static int nextTextBeginDraw(Bitmap bitmap) {
        int begin = 0;
        for (int x = 0; x < bitmap.getWidth(); x++) {
            for (int y = 0; y < bitmap.getHeight(); y++) {
                if (bitmap.getPixel(x, y) != Color.WHITE) {
                    begin = x;
                }
            }
        }
        return begin;
    }

    /**
     * 图片转3d,并将外框最低点模型移到原点
     *
     * @param img2D
     * @return
     */
    private static Data3D convert3D0(Bitmap img2D) {
        List<Triangle> list = new ArrayList<>();
        Data3D data3D = new Data3D(list);

        boolean bitInverted = false;
        int intMinDepth = 0;// 图片原本的z最低
        int intMaxDepth = 0;// 图片原本的z最高
        int intImageWidth = img2D.getWidth();
        int intImageHeight = img2D.getHeight();

        int grayImg[][] = new int[intImageWidth][intImageHeight];

        for (int y = 0; y < intImageHeight; y++) {
            for (int x = 0; x < intImageWidth; x++) {
                grayImg[x][y] = img2D.getPixel(x, y);
            }
        }
        img2D.recycle();

        forGray(grayImg, 0, 0, intImageWidth, intImageHeight);
        int threshold = calculateThreshold(grayImg, 0, 0, intImageWidth, intImageHeight);

        int intHeights[][] = new int[intImageWidth + 2][intImageHeight + 2];
        // 用于减少重复计算的点
        byte bitTopDone[][] = new byte[intImageWidth + 2][intImageHeight + 2];

        // 为了模型封闭,矩阵放宽,所以横列+2
        // calculate iniMinDepth
        for (int x = 0; x < intImageWidth; x++) {
            for (int y = 0; y < intImageHeight; y++) {
                if (bitInverted) {
                    intHeights[x + 1][intImageHeight - y] = grayImg[x][y] > threshold ? 255 : 0;
                } else {
                    intHeights[x + 1][intImageHeight - y] = 255 - (grayImg[x][y] > threshold ? 255 : 0);
                }
                if (intHeights[x + 1][intImageHeight - y] < intMinDepth) {
                    intMinDepth = intHeights[x + 1][intImageHeight - y];
                }
                if (intHeights[x + 1][intImageHeight - y] > intMaxDepth) {
                    intMaxDepth = intHeights[x + 1][intImageHeight - y];
                }
            }
        }

        //计算出最大高度
        // 计算出最大高度
        int calculateHMax = (int) (USB_HEIGHT / 2);
        for (int x = 0; x < intImageWidth; x++) {
            for (int y = 0; y < intImageHeight; y++) {
                intHeights[intImageWidth - x][intImageHeight - y] = calculateHMax
                        * (intHeights[intImageWidth - x][intImageHeight - y] - intMinDepth)
                        / (intMaxDepth - intMinDepth);
            }
        }
        // 计算
        // 利用color计算高度
        for (int x = 0; x < intImageWidth + 1; x++) {
            for (int y = 0; y < intImageHeight + 1; y++) {
                // 这个点还没被计算
                if (bitTopDone[x][y] == 0) {
                    // 为了减少计算量,排除没高度的区域
                    if (intHeights[x][y] > 0 || intHeights[x + 1][y] > 0 || intHeights[x][y + 1] > 0
                            || intHeights[x + 1][y + 1] > 0) {
                        int intBlockSize = 0;

                        boolean bitNoMatch = false;
                        // (x,y)点之后的图片最长边
                        int intMatchSize = 0;
                        int intTemp1 = intImageWidth - x;
                        int intTemp2 = intImageHeight - y;
                        if (intTemp1 > intTemp2) {
                            intMatchSize = intTemp1;
                        } else {
                            intMatchSize = intTemp2;
                        }

                        for (int i = 1; i < intMatchSize + 1; i++) {
                            for (int j = 0; j < intMatchSize + 1; j++) {
                                if (intHeights[x][y] != intHeights[x + i][y + j]
                                        || intHeights[x][y] != intHeights[x + j][y + i]) {
                                    bitNoMatch = true;// 与前面正方形区域高度不一致
                                    break;
                                }
                            }
                            if (bitNoMatch)
                                break;
                            else
                                intBlockSize = i - 1;// 记录高度一致的正方形大小
                        }

                        for (int i = 1; i < intBlockSize; i++) {
                            for (int j = 0; j < intBlockSize; j++) {
                                bitTopDone[x + i][y + j] = 1;// 记录被计算的正方形区域
                            }
                        }
                        intBlockSize += 1;// 为了模型是密封的,边的高度与区域的高度不一样

                        Triangle objTriangle1 = new Triangle();
                        objTriangle1.setFirstPoint(x, y, intHeights[x][y]);
                        objTriangle1.setSecodePoint(x + intBlockSize, y + intBlockSize, intHeights[x + intBlockSize][y
                                + intBlockSize]);
                        objTriangle1.setThridPoint(x, y + intBlockSize, intHeights[x][y + intBlockSize]);

                        Triangle objTriangle2 = new Triangle();
                        objTriangle2.setFirstPoint(x, y, intHeights[x][y]);
                        objTriangle2.setSecodePoint(x + intBlockSize, y, intHeights[x + intBlockSize][y]);
                        objTriangle2.setThridPoint(x + intBlockSize, y + intBlockSize, intHeights[x + intBlockSize][y
                                + intBlockSize]);

                        list.add(objTriangle1);
                        list.add(objTriangle2);
                    }
                }
            }
        }

        //
        // 补全(x == intImageWidth && y == 1)
        //
        if (intHeights[intImageWidth][1] > 0) {
            Triangle objTriangle3 = new Triangle();
            objTriangle3.setFirstPoint(intImageWidth, 1, intHeights[intImageWidth][1]);
            objTriangle3.setSecodePoint(intImageWidth + 1, 0, intHeights[intImageWidth + 1][0]);
            objTriangle3.setThridPoint(intImageWidth, 0, intHeights[intImageWidth][0]);

            Triangle objTriangle4 = new Triangle();
            objTriangle4.setFirstPoint(intImageWidth, 1, intHeights[intImageWidth][1]);
            objTriangle4.setSecodePoint(intImageWidth + 1, 0, intHeights[intImageWidth + 1][0]);
            objTriangle4.setThridPoint(intImageWidth + 1, 1, intHeights[intImageWidth + 1][1]);

            list.add(objTriangle3);
            list.add(objTriangle4);
        }

        //
        // 补全(x == 1 && y == intImageHeight)
        //
        if (intHeights[1][intImageHeight] > 0) {
            Triangle objTriangle5 = new Triangle();
            objTriangle5.setFirstPoint(1, intImageHeight, intHeights[1][intImageHeight]);
            objTriangle5.setSecodePoint(0, intImageHeight + 1, intHeights[0][intImageHeight + 1]);
            objTriangle5.setThridPoint(0, intImageHeight, intHeights[0][intImageHeight]);

            Triangle objTriangle6 = new Triangle();
            objTriangle6.setFirstPoint(1, intImageHeight, intHeights[1][intImageHeight]);
            objTriangle6.setSecodePoint(0, intImageHeight + 1, intHeights[0][intImageHeight + 1]);
            objTriangle6.setThridPoint(1, intImageHeight + 1, intHeights[1][intImageHeight + 1]);

            list.add(objTriangle5);
            list.add(objTriangle6);
        }
        int positiveSize = list.size();
        for (int i = 0; i < positiveSize; i++) {
            Triangle positive = list.get(i);
            Triangle reverse = new Triangle();
            reverse.setFirstPoint(positive.x1, positive.y1, 0 - positive.z1);
            reverse.setSecodePoint(positive.x2, positive.y2, 0 - positive.z2);
            reverse.setThridPoint(positive.x3, positive.y3, 0 - positive.z3);

            list.add(reverse);
        }
        data3D.calculateMaxAndMin();
        // add wall
        Point3D maxMidZ = new Point3D(data3D.max.x, data3D.max.y, data3D.max.z * INSIDE_THICKNESS_RATE);
        Point3D minMidZ = new Point3D(data3D.min.x, data3D.min.y, data3D.min.z * INSIDE_THICKNESS_RATE);
        List<Triangle> cubeMid = cuboid(minMidZ, maxMidZ);
        list.addAll(cubeMid);//TODO
        // 移动到原点
        Point3D org = new Point3D(0, 0, 0);
        if (!data3D.min.equals(org)) {
            for (int i = 0; i < list.size(); i++) {
                Triangle tri = list.get(i);
                tri.toMoveX(-data3D.min.x);
                tri.toMoveY(-data3D.min.y);
                tri.toMoveZ(-data3D.min.z);
            }
        }
        data3D.calculateMaxAndMin();
        return data3D;
    }

    /**
     * 将图片灰值化
     *
     * @param pic
     * @param beginX
     * @param beginY
     * @param width
     * @param height
     */
    public static void forGray(int[][] pic, int beginX, int beginY, int width, int height) {
        for (int x = beginX; x < beginX + width; x++) {
            for (int y = beginY; y < beginY + height; y++) {
                int red = ((pic[x][y] & 0x00FF0000) >> 16);
                int green = ((pic[x][y] & 0x0000FF00) >> 8);
                int blue = (pic[x][y] & 0x000000FF);
                pic[x][y] = (int) (red * 0.3 + green * 0.59 + blue * 0.11);// 灰度公式
            }
        }
    }

    /**
     * 图像二值化阀值 kittle算法
     */
    public static int calculateThreshold(int[][] picGray, int beginX, int beginY, int width, int height) {
        int sumGrayGrads = 0;
        int sumGrads = 0;
        for (int x = beginX + 1; x < beginX + width - 1; x++) {
            for (int y = beginY + 1; y < beginY + height - 1; y++) {
                // 求水平或垂直方向的最大梯度
                int Grads = Math.max(Math.abs(picGray[x][y + 1] - picGray[x][y - 1]), Math.abs(picGray[x + 1][y] - picGray[x - 1][y])); // max(xGrads,yGrads)
                sumGrads += Grads;
                // 梯度与当前点灰度的积
                sumGrayGrads += Grads * picGray[x][y];
            }
        }
        Log.e("convert3D", "sumGrayGrads " + sumGrayGrads + " sumGrads " + sumGrads);
        return sumGrayGrads / sumGrads;
    }

    public static STLFile toStlFile(Data3D data3D) {
        ByteBuffer mbb = ByteBuffer.allocateDirect(data3D.tris.size() * 9 * 4);
        // 数组排列用nativeOrder
        mbb.order(ByteOrder.nativeOrder());
        FloatBuffer fbV = mbb.asFloatBuffer();

        for (int i = 0; i < data3D.tris.size(); i++) {
            Triangle triangle = data3D.tris.get(i);
            fbV.put(triangle.x1);
            fbV.put(triangle.y1);
            fbV.put(triangle.z1);
            fbV.put(triangle.x2);
            fbV.put(triangle.y2);
            fbV.put(triangle.z2);
            fbV.put(triangle.x3);
            fbV.put(triangle.y3);
            fbV.put(triangle.z3);
        }
        fbV.position(0);
        //TODO
        mbb = ByteBuffer.allocateDirect(data3D.tris.size() * 9 * 4);
        // 数组排列用nativeOrder
        mbb.order(ByteOrder.nativeOrder());
        FloatBuffer fbN = mbb.asFloatBuffer();
        for (int i = 0; i < data3D.tris.size(); i++) {
            Triangle triangle = data3D.tris.get(i);
            triangle.calculateNormal();
            fbN.put(triangle.nx);
            fbN.put(triangle.ny);
            fbN.put(triangle.nz);
            fbN.put(triangle.nx);
            fbN.put(triangle.ny);
            fbN.put(triangle.nz);
            fbN.put(triangle.nx);
            fbN.put(triangle.ny);
            fbN.put(triangle.nz);

        }
        return new STLFile(data3D.tris.size(), new float[]{data3D.max.x, data3D.max.y, data3D.max.z}, new float[]{data3D.min.x, data3D.min.y, data3D.min.z}, fbV, fbN);
    }

    /**
     * 长方体
     *
     * @param min
     * @param max
     * @return
     */
    public static List<Triangle> cuboid(Point3D min, Point3D max) {
        List<Triangle> cube = new ArrayList<>(6 * 2);
        //1
        Triangle a = new Triangle();
        a.setFirstPoint(min.x, min.y, min.z);
        a.setSecodePoint(min.x, min.y, max.z);
        a.setThridPoint(min.x, max.y, max.z);

        Triangle b = new Triangle();
        b.setFirstPoint(min.x, min.y, min.z);
        b.setSecodePoint(min.x, max.y, min.z);
        b.setThridPoint(min.x, max.y, max.z);

        //2
        Triangle c = new Triangle();
        c.setFirstPoint(min.x, min.y, min.z);
        c.setSecodePoint(min.x, max.y, min.z);
        c.setThridPoint(max.x, max.y, min.z);

        Triangle d = new Triangle();
        d.setFirstPoint(min.x, min.y, min.z);
        d.setSecodePoint(max.x, min.y, min.z);
        d.setThridPoint(max.x, max.y, min.z);

        //3
        Triangle e = new Triangle();
        e.setFirstPoint(min.x, min.y, min.z);
        e.setSecodePoint(min.x, min.y, max.z);
        e.setThridPoint(max.x, min.y, max.z);

        Triangle f = new Triangle();
        f.setFirstPoint(min.x, min.y, min.z);
        f.setSecodePoint(max.x, min.y, min.z);
        f.setThridPoint(max.x, min.y, max.z);

        //4
        Triangle g = new Triangle();
        g.setFirstPoint(max.x, min.y, min.z);
        g.setSecodePoint(max.x, min.y, max.z);
        g.setThridPoint(max.x, max.y, max.z);

        Triangle h = new Triangle();
        h.setFirstPoint(max.x, min.y, min.z);
        h.setSecodePoint(max.x, max.y, min.z);
        h.setThridPoint(max.x, max.y, max.z);

        //5
        Triangle i = new Triangle();
        i.setFirstPoint(min.x, max.y, min.z);
        i.setSecodePoint(min.x, max.y, max.z);
        i.setThridPoint(max.x, max.y, max.z);

        Triangle j = new Triangle();
        j.setFirstPoint(min.x, max.y, min.z);
        j.setSecodePoint(max.x, max.y, min.z);
        j.setThridPoint(max.x, max.y, max.z);

        //6
        Triangle k = new Triangle();
        k.setFirstPoint(min.x, min.y, max.z);
        k.setSecodePoint(min.x, max.y, max.z);
        k.setThridPoint(max.x, max.y, max.z);

        Triangle l = new Triangle();
        l.setFirstPoint(min.x, min.y, max.z);
        l.setSecodePoint(max.x, min.y, max.z);
        l.setThridPoint(max.x, max.y, max.z);

        cube.add(a);
        cube.add(b);

        cube.add(c);
        cube.add(d);

        cube.add(e);
        cube.add(f);

        cube.add(g);
        cube.add(h);

        cube.add(i);
        cube.add(j);

        cube.add(k);
        cube.add(l);

        return cube;
    }

    /**
     * 生成U盘插头
     * firstPoint(0,0,0)
     */
    private static Data3D generateUsbHead() {
        final float LENGTH_GAP = (USB_LENGTH - USB_H_LENGTH) / 2;
        final float HEIGHT_GAP = (USB_HEIGHT - USB_H_HEIGHT) / 2;

        Point3D a = new Point3D(0f, 0f, 0f);//左侧面左下角
        Point3D b = new Point3D(0f, USB_LENGTH, 0f);//左侧面左上角
        Point3D c = new Point3D(0f, 0f, USB_HEIGHT);//左侧面右下角
        Point3D d = new Point3D(0f, USB_LENGTH, USB_HEIGHT);//左侧面右下角
        Rectangular leftSide = new Rectangular(a, b, c, d);

        Point3D e = new Point3D(USB_WIDTH, 0f, 0f);//底面
        Point3D g = new Point3D(USB_WIDTH, 0f, USB_HEIGHT);
        Rectangular bottomSide = new Rectangular(a, e, c, g);

        Point3D f = new Point3D(USB_WIDTH, USB_LENGTH, 0f);//背面
        Rectangular backSide = new Rectangular(a, b, e, f);

        Point3D h = new Point3D(USB_WIDTH, USB_LENGTH, USB_HEIGHT);
        Rectangular topSide = new Rectangular(b, f, d, h);
        Rectangular frontSide = new Rectangular(c, d, g, h);
        //inside w:12.4fh:4f
        Point3D i = new Point3D(USB_WIDTH, LENGTH_GAP, HEIGHT_GAP);//e
        Point3D j = new Point3D(USB_WIDTH, LENGTH_GAP + USB_H_LENGTH, HEIGHT_GAP);//f
        Point3D k = new Point3D(USB_WIDTH, LENGTH_GAP, HEIGHT_GAP + USB_H_HEIGHT);//g
        Point3D l = new Point3D(USB_WIDTH, LENGTH_GAP + USB_H_LENGTH, HEIGHT_GAP + USB_H_HEIGHT);//h


        Point3D m = new Point3D(USB_WIDTH - USB_H_WIDTH, LENGTH_GAP, HEIGHT_GAP);
        Point3D n = new Point3D(USB_WIDTH - USB_H_WIDTH, LENGTH_GAP + USB_H_LENGTH, HEIGHT_GAP);
        Point3D o = new Point3D(USB_WIDTH - USB_H_WIDTH, LENGTH_GAP, HEIGHT_GAP + USB_H_HEIGHT);
        Point3D p = new Point3D(USB_WIDTH - USB_H_WIDTH, LENGTH_GAP + USB_H_LENGTH, HEIGHT_GAP + USB_H_HEIGHT);
        Rectangular iLeftSide = new Rectangular(m, n, o, p);
        Rectangular iBottomSide = new Rectangular(m, i, o, k);
        Rectangular iBackSide = new Rectangular(m, n, i, j);
        Rectangular iTopSide = new Rectangular(n, j, p, l);
        Rectangular iFrontSide = new Rectangular(o, p, k, l);

        //positive side
        //f*r***t*h
        //**j***l**
        //**i***k**
        //e*q***s*g
        Point3D q = new Point3D(USB_WIDTH, 0f, HEIGHT_GAP);//e
        Point3D r = new Point3D(USB_WIDTH, USB_LENGTH, HEIGHT_GAP);//f
        Point3D s = new Point3D(USB_WIDTH, 0f, HEIGHT_GAP + USB_H_HEIGHT);//g
        Point3D t = new Point3D(USB_WIDTH, USB_LENGTH, HEIGHT_GAP + USB_H_HEIGHT);//h
        Rectangular positiveSide1 = new Rectangular(e, f, q, r);
        Rectangular positiveSide2 = new Rectangular(j, r, l, t);
        Rectangular positiveSide3 = new Rectangular(q, i, s, k);
        Rectangular positiveSide4 = new Rectangular(s, t, g, h);

        List<Triangle> triangles = new ArrayList<>();
        triangles.add(leftSide.tri1);//外框
        triangles.add(leftSide.tri2);
        triangles.add(bottomSide.tri1);
        triangles.add(bottomSide.tri2);
        triangles.add(backSide.tri1);
        triangles.add(backSide.tri2);
        triangles.add(topSide.tri1);
        triangles.add(topSide.tri2);
        triangles.add(frontSide.tri1);
        triangles.add(frontSide.tri2);

        triangles.add(iLeftSide.tri1);//内框
        triangles.add(iLeftSide.tri2);
        triangles.add(iBottomSide.tri1);
        triangles.add(iBottomSide.tri2);
        triangles.add(iBackSide.tri1);
        triangles.add(iBackSide.tri2);
        triangles.add(iTopSide.tri1);
        triangles.add(iTopSide.tri2);
        triangles.add(iFrontSide.tri1);
        triangles.add(iFrontSide.tri2);

        triangles.add(positiveSide1.tri1);//正面
        triangles.add(positiveSide1.tri2);
        triangles.add(positiveSide2.tri1);
        triangles.add(positiveSide2.tri2);
        triangles.add(positiveSide3.tri1);
        triangles.add(positiveSide3.tri2);
        triangles.add(positiveSide4.tri1);
        triangles.add(positiveSide4.tri2);

        Data3D usbHead = new Data3D(triangles);
        usbHead.min.set(a.x, a.y, a.z);
        usbHead.max.set(h.x, h.y, h.y);
        return usbHead;
    }

    public static void multiWord3DUsbHead(Data3D word3D) {
        Data3D usbHead = generateUsbHead();
        for (int i = 0; i < usbHead.tris.size(); i++) {
            Triangle tri = usbHead.tris.get(i);
            tri.toMoveX(word3D.max.x);
        }
        word3D.tris.addAll(usbHead.tris);
        word3D.updateMax(usbHead.max.x, usbHead.max.y, usbHead.max.z);
        return;
    }

}
